import datetime

from rest_framework import mixins
from rest_framework import generics
from rest_framework.views import APIView
from rest_framework.permissions import IsAuthenticatedOrReadOnly, SAFE_METHODS, IsAuthenticated
from rest_framework.viewsets import GenericViewSet
from rest_framework.response import Response
from rest_framework.decorators import api_view
from django.http import Http404
from django.views.decorators.cache import cache_page
from django.utils.decorators import method_decorator
from django.db.models import Q

from .models import Blog, BlogPV, DailyPV, Category
from .serializers import BlogSerializer, BlogPVSerializer, BlogListSerialize, DailyPVSerializer
from .permissions import IsAuthor, IsSuperuser
from .pagination import BlogPagination


# Create your views here.
class BlogViewSet(mixins.CreateModelMixin,
                  mixins.RetrieveModelMixin,
                  mixins.UpdateModelMixin,
                  mixins.DestroyModelMixin,
                  GenericViewSet):
    """
    除了List外其他方法均有
    """
    queryset = Blog.objects.all()
    serializer_class = BlogSerializer

    def get_permissions(self):
        permission_list = [IsAuthenticatedOrReadOnly]
        if self.request.method not in SAFE_METHODS:
            permission_list.append(IsAuthor)
        return [permission() for permission in permission_list]

    def perform_create(self, serializer):
        # 无论什么权限，作者只能是自己
        serializer.save(author=self.request.user)

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        # 使用cookie存储阅读统计量
        cookie_key = instance.increase_pv(request)
        response = Response(serializer.data)
        last_min_of_today = datetime.datetime.combine(datetime.date.today(), datetime.time.max)
        response.set_cookie(key=cookie_key, value="1", expires=last_min_of_today, httponly=True)
        return response


class BlogListView(generics.ListAPIView):
    queryset = Blog.objects.none()  # no use because we implement the get_queryset()
    serializer_class = BlogListSerialize
    pagination_class = BlogPagination

    def get_queryset(self):
        category = self.request.query_params.get('category')
        year = self.request.query_params.get('year')
        month = self.request.query_params.get('month')
        search_keywords = self.request.query_params.get('key')
        queryset = Blog.objects.all()
        if category:
            try:
                # 按照id查找
                queryset = queryset.filter(category=category)
            except ValueError:
                # 按照name查找
                queryset = queryset.filter(category__name=category)
        if year:
            queryset = queryset.filter(create_time__year=year)
        if month:
            queryset = queryset.filter(create_time__month=month)
        if search_keywords:
            query = None
            for keyword in search_keywords.strip().split(' '):
                condition = Q(title__icontains=keyword)
                query = (condition | query) if query else condition
            queryset = queryset.filter(query)
        return queryset


class BlogDateView(APIView):
    @classmethod
    def formatDate(cls, date: datetime.date):
        return date.strftime("%Y-%m")

    @method_decorator(cache_page(2 * 60 * 60, cache="database", key_prefix="blog_date"))
    def get(self, request):
        dates = Blog.objects.dates('create_time', 'month', order='DESC')
        res_data = {}
        for date in dates:
            # date是datetime.date类型
            key = BlogDateView.formatDate(date)
            res_data[key] = Blog.objects.filter(create_time__year=date.year, create_time__month=date.month).count()
        return Response(res_data)


class BlogCategoryView(APIView):
    @method_decorator(cache_page(4 * 60 * 60, cache="database", key_prefix="blog_category"))
    def get(self, request):
        category = Category.objects.values_list('id', 'name')
        res_data = {}
        for category_id, name in category:
            res_data[name] = {"id": category_id, "count": Blog.objects.filter(category=category_id).count()}
        return Response(res_data)


class DailyPVView(generics.ListAPIView):
    queryset = DailyPV.objects.none()  # no use because we implement the get_queryset()
    serializer_class = DailyPVSerializer
    permission_classes = [IsSuperuser]  # 只允许超级管理员查询
    pagination_class = None

    def get_queryset(self):
        start = self.request.query_params.get('start', '1970-01-01')
        end = self.request.query_params.get('end', '2999-12-31')
        return DailyPV.objects.filter(date__range=[start, end])


@api_view(['GET'])
def get_past_seven_days_pv(request):
    """
    查询过去7天的总阅读量
    """
    today = datetime.date.today()
    seven_days_ago = today - datetime.timedelta(days=6)
    serializer = DailyPVSerializer(DailyPV.objects.filter(date__range=[seven_days_ago, today]), many=True)
    return Response(serializer.data)


@api_view(['GET'])
def get_today_pv(request):
    """
    查询当天的总访问量
    """
    date = datetime.date.today()
    obj = generics.get_object_or_404(DailyPV.objects.all(), date=date)
    return Response(DailyPVSerializer(obj).data)


class BlogPVView(generics.RetrieveAPIView):
    queryset = BlogPV.objects.all()
    serializer_class = BlogPVSerializer
    permission_classes = [IsAuthenticated]

    def get_object(self):
        blog_id = self.request.query_params.get('id')
        if not blog_id:
            raise Http404
        obj = generics.get_object_or_404(self.get_queryset(), blog__pk=blog_id)
        self.check_object_permissions(self.request, obj)  # DO NOT forget check permission
        return obj

    def retrieve(self, request, *args, **kwargs):
        instance = self.get_object()
        serializer = self.get_serializer(instance)
        data = serializer.data
        data['blog_id'] = self.request.query_params.get('id')  # add blog id in response
        return Response(data)
